package w83b.util.jdbc;

import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;

import w83b.w83bBeans.W83bBaseBeanBD;
import w83b.w83bBeans.W83bUsuarioXLNetsBean;
import w83b.w83bUtilidadesComunes.W83bClsConstantes;
import w83b.w83bUtilidadesComunes.W83bClsTrazas;
import es.ejie.frmk.listeners.base.Q70ListenerUtils;

// TODO: Auto-generated Javadoc
/**
 * The Class U66aDataBase.
 *
 * @author Deusto Sistemas
 */
public abstract class W83bDataBase {
	
	/**
	 * Instantiates a new u66a data base.
	 */
	public W83bDataBase() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * Gets the connection.
	 *
	 * @return the connection
	 * @throws NamingException the naming exception
	 * @throws SQLException the sQL exception
	 */
	public static Connection getConnection() throws NamingException, SQLException {
		Connection con; // NOPMD
		Hashtable ht=new Hashtable(); 
		ht.put(Context.INITIAL_CONTEXT_FACTORY,Q70ListenerUtils.getApplicationProperty("INITIAL_CONTEXT_FACTORY")); 
		  Context ctx=new InitialContext(ht);
		  DataSource ds=(DataSource)ctx.lookup(Q70ListenerUtils.getApplicationProperty("DATA_SOURCE"));
		  con=ds.getConnection();
		return con;
	}
	
	/**
	 * Execute query.
	 *
	 * @throws Exception the exception
	 */
	public static List executeQuery(String sql, List parametros, Class bean, W83bUsuarioXLNetsBean userBean,Object otrosValores) throws Exception {
		
				Connection con = null; //NOPMD
				PreparedStatement st = null; //NOPMD
				List resultado = new ArrayList();
		try { 
				
				W83bClsTrazas.formatTraza(userBean,"query->"+sql);
				W83bClsTrazas.formatTraza(userBean,"Parámetros->"+parametros.toString());					
				long milisegundos = System.currentTimeMillis();
				con = getConnection();
			    st=con.prepareStatement(sql);
			    if (parametros!=null && parametros.size()>0){
			    	for (int i=0;i<parametros.size();i++){
			    		st.setObject(i+1, parametros.get(i));
			    	}
			    }
			    
			    ResultSet res=st.executeQuery(); //NOPMD
			    resultado = getRSData(res,bean,otrosValores);				    
				W83bClsTrazas.formatTraza(userBean,"Query OK -> "+ (System.currentTimeMillis()- milisegundos) + " ms");	    

		} catch(Exception e ) {
				
				throw e;
		}  finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			}   
		} 
		return resultado;	
	}
	
	/**
	 * Execute query.
	 *
	 * @throws Exception the exception
	 */
	public static HashMap executeQueryHashMap(String sql, List parametros, Class bean, W83bUsuarioXLNetsBean userBean,Object otrosValores,String clave) throws Exception {//NOPMD
				Connection con = null;//NOPMD
				PreparedStatement st = null;//NOPMD
				HashMap resultado = new HashMap();
		try{
		
				W83bClsTrazas.formatTraza(userBean,"query->"+sql);
				W83bClsTrazas.formatTraza(userBean,"Parámetros->"+parametros.toString());					
				long milisegundos = System.currentTimeMillis();				
				con = getConnection();
				st=con.prepareStatement(sql);
				if (parametros!=null && parametros.size()>0){
					for (int i=0;i<parametros.size();i++){
						st.setObject(i+1, parametros.get(i));
					}
				}	
				ResultSet res=st.executeQuery(); //NOPMD
				clave = clave.substring(0,1).toUpperCase() + clave.substring(1);
				resultado = getRSDataHashMap(res,bean,otrosValores,clave);

				W83bClsTrazas.formatTraza(userBean,"Query OK -> "+ (System.currentTimeMillis()- milisegundos) + " ms");	    
		
		} catch(Exception e ) {
			throw e;
		}  finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			}   
		} 
			return resultado;	
	}
	
	/**
	 * Execute query.
	 *
	 * @throws Exception the exception
	 */
	public static List executeQuery(String sql, List parametros,W83bUsuarioXLNetsBean usuarioBean) throws Exception {
			
			List listaObjetos = new ArrayList();
			Connection con = null; // NOPMD
			PreparedStatement st = null; // NOPMD
		try{
			W83bClsTrazas.formatTraza(usuarioBean,"query->"+sql);
			W83bClsTrazas.formatTraza(usuarioBean,"Parámetros->"+parametros.toString());			
			long milisegundos = System.currentTimeMillis();			
			con = getConnection();
			st=con.prepareStatement(sql);
			if (parametros!=null && parametros.size()>0){
				for (int i=0;i<parametros.size();i++){
					st.setObject(i+1, parametros.get(i));
				}
			}
			ResultSet res=st.executeQuery(); // NOPMD
			ResultSetMetaData rsMetaData = res.getMetaData();
		    int numberOfColumns = rsMetaData.getColumnCount();
			while(res.next()){
				HashMap mapaFila = new HashMap();//NOPMD
				for (int i = 1; i < numberOfColumns + 1; i++) {
				   String columnName = rsMetaData.getColumnName(i);
				   // Get the name of the column's table name
				   mapaFila.put(columnName, res.getObject(columnName));
				}
				listaObjetos.add(mapaFila);			      
			}
			
			W83bClsTrazas.formatTraza(usuarioBean,"Query OK -> "+ (System.currentTimeMillis()- milisegundos) + " ms");	    
		
		} catch(Exception e ) {
			throw e;
		}  finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			}   
		} 
			return listaObjetos;			
	}
	
	/** Ejecuta una consulta que solo tiene una columna
	 * Execute query.
	 *
	 * @throws Exception the exception
	 */
	public static List executeSimpleQuery(String sql, List parametros,W83bUsuarioXLNetsBean usuarioBean) throws Exception {
		Connection con = null; // NOPMD
		PreparedStatement st = null; // NOPMD
		List listaObjetos = new ArrayList();
			try{
				W83bClsTrazas.formatTraza(usuarioBean,"query->"+sql);
				W83bClsTrazas.formatTraza(usuarioBean,"Parámetros->"+parametros.toString());		
				long milisegundos = System.currentTimeMillis();
				con = getConnection();
				st=con.prepareStatement(sql);
				if (parametros!=null && parametros.size()>0){
					for (int i=0;i<parametros.size();i++){
						st.setObject(i+1, parametros.get(i));
					}
				}
				ResultSet res=st.executeQuery(); // NOPMD 
				while(res.next()){
					listaObjetos.add(res.getObject(1));
				}

				W83bClsTrazas.formatTraza(usuarioBean,"Query OK -> "+ (System.currentTimeMillis()- milisegundos) + " ms");	    
				
		} catch(Exception e ) {
			throw e;
		}  finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			} 
		} 
		return listaObjetos;	
	}
	
	/** Ejecuta una consulta que solo tiene una columna
	 * Execute query.
	 *
	 * @throws Exception the exception
	 */
	public static List executeSimpleQuerySinTrazas(String sql, List parametros,W83bUsuarioXLNetsBean usuarioBean) throws Exception {
		Connection con = null; // NOPMD
		PreparedStatement st = null; // NOPMD
		List listaObjetos = new ArrayList();
		try{
			con = getConnection();
			st=con.prepareStatement(sql);
			if (parametros!=null && parametros.size()>0){
				for (int i=0;i<parametros.size();i++){
					st.setObject(i+1, parametros.get(i));
				}
			}
			ResultSet res=st.executeQuery(); // NOPMD b
			while(res.next()){
				listaObjetos.add(res.getObject(1));
			}

		} catch(Exception e ) {
			throw e;
		} finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			}  
		} 
		return listaObjetos;			
	}

	
	/**
	 * Gets the rS data.
	 *
	 * @param res the res
	 * @return the rS data
	 * @throws SQLException the sQL exception
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	private static HashMap getRSDataHashMap(ResultSet res, Class clase, Object otrosValores,String clave) throws Exception {
		HashMap lista = new HashMap();
		while (res.next()){		    
			W83bBaseBeanBD bean = (W83bBaseBeanBD)clase.newInstance();
			bean.rowToBean(res,otrosValores);
			lista.put(bean.getClass().getMethod("get"+clave, null).invoke(bean, null),bean);
		}
		
		return lista;
	}

	/**
	 * Gets the rS data.
	 *
	 * @param res the res
	 * @return the rS data
	 * @throws SQLException the sQL exception
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	private static List getRSData(ResultSet res, Class clase, Object otrosValores) throws Exception {
		List lista = new ArrayList();
		//PARTES COOMENTADAS, PARA OPTIMIZAR LA VELOCIDAD
		//A LA HORA DE METER LOS RESULTADOS EN LA QUERIE
		/*long milis = System.currentTimeMillis();
		long milisAnt = System.currentTimeMillis();
		int i=0;*/
		while (res.next()){		    
    	  W83bBaseBeanBD bean = (W83bBaseBeanBD)clase.newInstance();
	      bean.rowToBean(res,otrosValores);
/*	      if(i%100==0){
	    	  W83bClsTrazas.trazaError(null,"Query OK -> "+ (System.currentTimeMillis()-milis) + " ms - "+i + "- ant - "+((System.currentTimeMillis()-milis)-milisAnt),null);
	    	  milisAnt = System.currentTimeMillis()-milis;
	      }
	      i++;*/
	      lista.add(bean);
		}
	
		return lista;
	}


private static void meterVariableBlob(PreparedStatement st, int posicion, InputStream parameter,int size) throws SQLException{
	
		st.setBinaryStream(posicion, parameter,size);
}

	private static void meterVariableSql(PreparedStatement st, int posicion, Object parameter) throws SQLException{
		
		if(W83bClsConstantes.NULL_DOUBLE.equals(parameter.toString())){
			st.setNull(posicion, Types.DOUBLE);
		}else
		if(W83bClsConstantes.NULL_STRING.equals(parameter.toString())){
			st.setNull(posicion, Types.VARCHAR);
		}else
		if(W83bClsConstantes.NULL_INTEGER.equals(parameter.toString())){
			st.setNull(posicion, Types.INTEGER);
		}else
		if(W83bClsConstantes.NULL_FLOAT.equals(parameter.toString())){
			st.setNull(posicion, Types.FLOAT);
		}else
		if(W83bClsConstantes.NULL_DATE.equals(parameter.toString())){
			st.setNull(posicion, Types.DATE);
		}else
		if(W83bClsConstantes.NULL_BLOB.equals(parameter.toString())){
			st.setNull(posicion, Types.BLOB);
		}else
		
		if(StringUtils.isNotEmpty(parameter.toString())){
			st.setObject(posicion, parameter);
		}
	}
	
	/**
	 * Ejecuta un movimiento en la BD.
	 * Usaremos en la sql para poner las variables '?' y meter en 'parameters' los valores correspondientes
	 * La función posteriormente usa meterVariableSql, para insertar estos valores en la sql según el tipo que
	 *  sean. 
	 *  Si el valor que se desea usar para insertarlo en la tabla es nulo en vez de null usar los valores
	 *  de las constantes habilitado para ello. (NULL_DOUBLE, NULL_STRING,...)	 * 
	 *
	 * @param con the con
	 * @param sql the sql
	 * @param parameters the parameters
	 * @return the int
	 * @throws Exception 
	 */
	public static int executeTableMovement(String sql, List parameters,W83bUsuarioXLNetsBean usuarioBean) throws Exception {
		Connection con = null; // NOPMD
		PreparedStatement st = null; // NOPMD
		int resultadoInt = 0;
		try{
			con = getConnection();
			st=con.prepareStatement(sql);		
			W83bClsTrazas.traza(usuarioBean,"PreparedStatement creado: " + sql);
			  if (parameters!=null && parameters.size()>0){
				  for (int i=0;i<parameters.size();i++){
					  meterVariableSql(st,i+1,parameters.get(i));
					  W83bClsTrazas.traza(usuarioBean,"parametro " + (i+1) + ": " + parameters.get(i));
				  }
			  }
			  resultadoInt = st.executeUpdate();
		} catch(Exception e ) {
			throw e;
		} finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			}   
		} 
		return resultadoInt;
	}
	
	
	/**
	 * Ejecuta un movimiento en la BD.
	 * Usaremos en la sql para poner las variables '?' y meter en 'parameters' los valores correspondientes
	 * La función posteriormente usa meterVariableSql, para insertar estos valores en la sql según el tipo que
	 *  sean. 
	 *  Si el valor que se desea usar para insertarlo en la tabla es nulo en vez de null usar los valores
	 *  de las constantes habilitado para ello. (NULL_DOUBLE, NULL_STRING,...)	 * 
	 *
	 * @param con the con
	 * @param sql the sql
	 * @param parameters the parameters
	 * @return the int
	 * @throws Exception 
	 */
	public static int executeTableMovementDeleg(String sql, List parameters,W83bUsuarioXLNetsBean usuarioBean) throws Exception {
		Connection con = null; // NOPMD
		PreparedStatement st = null; // NOPMD
		int resultadoInt = 0;
		try{
			//IDENTIFICAR USUARIO
			identificarUsuarioAuditor(usuarioBean.getIdUsuario());
			
			con = getConnection();
		    st=con.prepareStatement(sql);
			
			W83bClsTrazas.traza(usuarioBean,"PreparedStatement creado: " + sql);
			  if (parameters!=null && parameters.size()>0){
				  for (int i=0;i<parameters.size();i++){
					 
					  meterVariableSql(st,i+1,parameters.get(i));
					  W83bClsTrazas.traza(usuarioBean,"parametro " + (i+1) + ": " + parameters.get(i));
				  }
			  }
			  resultadoInt = st.executeUpdate();
			  
			  //TERMINAR USUARIO
			  W83bDataBase.terminarUsuarioAuditor();
			
		} catch(Exception e ) {
			throw e;
		} finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			}   
		} 
		return resultadoInt;
	}
	
	public static int executeBlobTableMovement(String sql, List parameters,int size,W83bUsuarioXLNetsBean usuarioBean) throws Exception {
		Connection con = null; // NOPMD
		PreparedStatement st = null; // NOPMD
		int resul = 0;
		try{
			con = getConnection();
		    st=con.prepareStatement(sql);
			
			W83bClsTrazas.traza(usuarioBean,"PreparedStatement creado: " + sql);
			  if (parameters!=null && parameters.size()>0){
				  for (int i=0;i<parameters.size();i++){
					  
					  if(null!=parameters.get(i)){
						  if (parameters.get(i) instanceof InputStream)
						  {
							  meterVariableBlob (st,i+1,(InputStream)parameters.get(i),size);
							  W83bClsTrazas.traza(usuarioBean,"parametro " + (i+1) + ": " + parameters.get(i));
							  continue;
						  }
					  }
					  meterVariableSql(st,i+1,parameters.get(i));
					  W83bClsTrazas.traza(usuarioBean,"parametro " + (i+1) + ": " + parameters.get(i));
				  }
			  }
			   resul=st.executeUpdate();
		} catch(Exception e ) {
			throw e;
		} finally { 
			if (st!=null){
				st.close(); 
			}
			if (con!=null){
				con.close(); 
			} 
		} 
		  return resul;
	}
	
	/*
	 * Funciones para sacar del resultSet el valor de una columna
	 */
	public static String getStringFromRS(ResultSet rs, String column){
		try {
			return rs.getString(column);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return "";
		}
	}	
	public static int getIntegerFromRS(ResultSet rs, String column){
		try {
			return rs.getInt(column);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return -1;
		}
	}
	public static BigDecimal getBigDecimalFromRS(ResultSet rs, String column){
		try {
			return rs.getBigDecimal(column);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return new BigDecimal(0);
		}
	}
	public static Blob getBlobFromRS(ResultSet rs, String column){
		try {
			return rs.getBlob(column);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}
	public static Date getDateFromRS(ResultSet rs, String column){
		try {
			return rs.getDate(column);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}
	public static double getDoubleFromRS(ResultSet rs, String column){
		try {
			return rs.getDouble(column);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return 0;
		}
	}
	public static void identificarUsuarioAuditor(String idUsuario) throws Exception
	{
		Connection con = null; // NOPMD
		CallableStatement cs=null;//NOPMD	
		try{
			String strEntornoAplic=Q70ListenerUtils.getApplicationProperty("ENTORNO_W83B");
			
			if(!"LOCAL".equals(strEntornoAplic)){
					con = W83bDataBase.getConnection();
				    cs = con.prepareCall("{CALL SYSAUDITOR.IDENTIFICA_USUARIO(?)}");
				    cs.setObject(1, idUsuario);
				    cs.execute();
				
			 }	  
		} catch(Exception e ) {
			throw e;
		} finally { 
			if (cs!=null){
				cs.close(); 
			}
			if (con!=null){
				con.close();
			}
		} 	
	}
	
	public static void terminarUsuarioAuditor() throws Exception{
		Connection con = null; // NOPMD
		CallableStatement cs=null;//NOPMD
		try{
			String strEntornoAplic=Q70ListenerUtils.getApplicationProperty("ENTORNO_W83B");
			if(!"LOCAL".equals(strEntornoAplic)){
				con=W83bDataBase.getConnection();
				cs =con.prepareCall("{CALL SYSAUDITOR.TERMINA_USUARIO()}");
				cs.execute();
			}
		} catch(Exception e ) {
			throw e;
		} finally { 
			if (cs!=null){
				cs.close(); 
			}
			 if (con!=null){
				con.close();
			}
		} 

	}
	
}